package server

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/redis/go-redis/v9"
)

// SessionStore 定义会话存储接口
type SessionStore interface {
	// SaveClient 保存客户端会话信息
	SaveClient(clientID string, serverID string) error

	// RemoveClient 移除客户端会话信息
	RemoveClient(clientID string) error

	// GetClientServer 获取客户端所在的服务器ID
	GetClientServer(clientID string) (string, error)

	// SaveSubscription 保存订阅信息
	SaveSubscription(clientID string, topic string) error

	// RemoveSubscription 移除订阅信息
	RemoveSubscription(clientID string, topic string) error

	// GetTopicSubscribers 获取主题的所有订阅者
	GetTopicSubscribers(topic string) ([]string, error)

	// Close 关闭会话存储
	Close() error
}

// MemorySessionStore 内存会话存储实现
type MemorySessionStore struct {
	// 客户端映射表，key是客户端ID，value是服务器ID
	clients map[string]string

	// 订阅映射表，key是topic，value是订阅该topic的客户端ID集合
	subscriptions map[string]map[string]struct{}
}

// NewMemorySessionStore 创建内存会话存储
func NewMemorySessionStore() *MemorySessionStore {
	return &MemorySessionStore{
		clients:       make(map[string]string),
		subscriptions: make(map[string]map[string]struct{}),
	}
}

// SaveClient 保存客户端会话信息
func (s *MemorySessionStore) SaveClient(clientID string, serverID string) error {
	s.clients[clientID] = serverID
	return nil
}

// RemoveClient 移除客户端会话信息
func (s *MemorySessionStore) RemoveClient(clientID string) error {
	delete(s.clients, clientID)
	return nil
}

// GetClientServer 获取客户端所在的服务器ID
func (s *MemorySessionStore) GetClientServer(clientID string) (string, error) {
	serverID, exists := s.clients[clientID]
	if !exists {
		return "", fmt.Errorf("client not found: %s", clientID)
	}
	return serverID, nil
}

// SaveSubscription 保存订阅信息
func (s *MemorySessionStore) SaveSubscription(clientID string, topic string) error {
	if _, exists := s.subscriptions[topic]; !exists {
		s.subscriptions[topic] = make(map[string]struct{})
	}
	s.subscriptions[topic][clientID] = struct{}{}
	return nil
}

// RemoveSubscription 移除订阅信息
func (s *MemorySessionStore) RemoveSubscription(clientID string, topic string) error {
	if subscribers, exists := s.subscriptions[topic]; exists {
		delete(subscribers, clientID)
		if len(subscribers) == 0 {
			delete(s.subscriptions, topic)
		}
	}
	return nil
}

// GetTopicSubscribers 获取主题的所有订阅者
func (s *MemorySessionStore) GetTopicSubscribers(topic string) ([]string, error) {
	subscribers, exists := s.subscriptions[topic]
	if !exists {
		return []string{}, nil
	}

	result := make([]string, 0, len(subscribers))
	for clientID := range subscribers {
		result = append(result, clientID)
	}
	return result, nil
}

// Close 关闭会话存储
func (s *MemorySessionStore) Close() error {
	// 内存存储不需要关闭
	return nil
}

// RedisSessionStore Redis会话存储实现
type RedisSessionStore struct {
	// Redis客户端
	client *redis.Client

	// 服务器ID
	serverID string

	// 服务器地址，用于RPC调用
	serverAddr string

	// 键前缀
	keyPrefix string

	// 会话过期时间
	sessionTTL time.Duration

	// 消息订阅
	pubsub *redis.PubSub

	// 消息处理函数
	messageHandler func(serverID, clientID string, message []byte) error

	// 上下文
	ctx context.Context

	// 取消函数
	cancel context.CancelFunc
}

// RedisSessionOptions Redis会话存储选项
type RedisSessionOptions struct {
	// Redis地址
	Addr string

	// Redis密码
	Password string

	// Redis数据库
	DB int

	// 服务器ID
	ServerID string

	// 服务器地址，用于RPC调用，格式为 "IP:端口"
	ServerAddr string

	// 键前缀
	KeyPrefix string

	// 会话过期时间
	SessionTTL time.Duration
}

// DefaultRedisSessionOptions 默认Redis会话存储选项
func DefaultRedisSessionOptions() RedisSessionOptions {
	return RedisSessionOptions{
		Addr:       "localhost:6379",
		Password:   "",
		DB:         0,
		ServerID:   "server1",
		ServerAddr: "localhost:8081",
		KeyPrefix:  "lcs:",
		SessionTTL: time.Hour * 24,
	}
}

// NewRedisSessionStore 创建Redis会话存储
func NewRedisSessionStore(options RedisSessionOptions) *RedisSessionStore {
	client := redis.NewClient(&redis.Options{
		Addr:     options.Addr,
		Password: options.Password,
		DB:       options.DB,
	})

	// 创建上下文
	ctx, cancel := context.WithCancel(context.Background())

	return &RedisSessionStore{
		client:     client,
		serverID:   options.ServerID,
		serverAddr: options.ServerAddr,
		keyPrefix:  options.KeyPrefix,
		sessionTTL: options.SessionTTL,
		ctx:        ctx,
		cancel:     cancel,
	}
}

// clientKey 生成客户端键
func (s *RedisSessionStore) clientKey(clientID string) string {
	return fmt.Sprintf("%sclient:%s", s.keyPrefix, clientID)
}

// topicKey 生成主题键
func (s *RedisSessionStore) topicKey(topic string) string {
	return fmt.Sprintf("%stopic:%s", s.keyPrefix, topic)
}

// SaveClient 保存客户端会话信息
func (s *RedisSessionStore) SaveClient(clientID string, serverID string) error {
	// 创建客户端信息，包含服务器ID和地址
	info := ClientInfo{
		ID:          clientID,
		ServerID:    serverID,
		ServerAddr:  s.serverAddr,
		ConnectedAt: time.Now(),
	}

	// 将客户端信息序列化为JSON
	infoBytes, err := json.Marshal(info)
	if err != nil {
		return err
	}

	// 存储到Redis
	ctx := context.Background()
	key := s.clientKey(clientID)
	return s.client.Set(ctx, key, string(infoBytes), s.sessionTTL).Err()
}

// RemoveClient 移除客户端会话信息
func (s *RedisSessionStore) RemoveClient(clientID string) error {
	ctx := context.Background()
	key := s.clientKey(clientID)
	return s.client.Del(ctx, key).Err()
}

// GetClientInfo 获取客户端信息
func (s *RedisSessionStore) GetClientInfo(clientID string) (*ClientInfo, error) {
	ctx := context.Background()
	key := s.clientKey(clientID)
	data, err := s.client.Get(ctx, key).Result()
	if err == redis.Nil {
		return nil, fmt.Errorf("client not found: %s", clientID)
	}
	if err != nil {
		return nil, err
	}

	// 解析客户端信息
	var info ClientInfo
	if err := json.Unmarshal([]byte(data), &info); err != nil {
		return nil, err
	}

	return &info, nil
}

// GetClientServer 获取客户端所在的服务器ID
func (s *RedisSessionStore) GetClientServer(clientID string) (string, error) {
	info, err := s.GetClientInfo(clientID)
	if err != nil {
		return "", err
	}
	return info.ServerID, nil
}

// SaveSubscription 保存订阅信息
func (s *RedisSessionStore) SaveSubscription(clientID string, topic string) error {
	ctx := context.Background()
	key := s.topicKey(topic)

	// 使用Redis集合存储订阅关系
	err := s.client.SAdd(ctx, key, clientID).Err()
	if err != nil {
		return err
	}

	// 设置过期时间
	return s.client.Expire(ctx, key, s.sessionTTL).Err()
}

// RemoveSubscription 移除订阅信息
func (s *RedisSessionStore) RemoveSubscription(clientID string, topic string) error {
	ctx := context.Background()
	key := s.topicKey(topic)

	// 从集合中移除客户端ID
	return s.client.SRem(ctx, key, clientID).Err()
}

// GetTopicSubscribers 获取主题的所有订阅者
func (s *RedisSessionStore) GetTopicSubscribers(topic string) ([]string, error) {
	ctx := context.Background()
	key := s.topicKey(topic)

	// 获取集合中的所有成员
	return s.client.SMembers(ctx, key).Result()
}

// messageChannelKey 生成消息通道键
func (s *RedisSessionStore) messageChannelKey(serverID string) string {
	return fmt.Sprintf("%smessage:%s", s.keyPrefix, serverID)
}

// StartMessageListener 启动消息监听器
func (s *RedisSessionStore) StartMessageListener(handler func(serverID, clientID string, message []byte) error) error {
	// 设置消息处理函数
	s.messageHandler = handler

	// 订阅服务器的消息通道
	channel := s.messageChannelKey(s.serverID)
	s.pubsub = s.client.Subscribe(s.ctx, channel)

	// 启动消息处理协程
	go func() {
		for {
			select {
			case <-s.ctx.Done():
				return
			case msg := <-s.pubsub.Channel():
				// 解析消息
				parts := strings.SplitN(msg.Payload, ":", 2)
				if len(parts) != 2 {
					log.Printf("Invalid message format: %s", msg.Payload)
					continue
				}

				clientID := parts[0]
				messageData, err := base64.StdEncoding.DecodeString(parts[1])
				if err != nil {
					log.Printf("Failed to decode message: %v", err)
					continue
				}

				// 处理消息
				if s.messageHandler != nil {
					if err := s.messageHandler(s.serverID, clientID, messageData); err != nil {
						log.Printf("Failed to handle message: %v", err)
					}
				}
			}
		}
	}()

	return nil
}

// SendMessageToServer 发送消息到指定服务器
func (s *RedisSessionStore) SendMessageToServer(serverID, clientID string, message []byte) error {
	// 如果是发送到当前服务器，直接处理
	if serverID == s.serverID && s.messageHandler != nil {
		return s.messageHandler(serverID, clientID, message)
	}

	// 否则，发送到目标服务器的消息通道
	channel := s.messageChannelKey(serverID)

	// 将消息编码为base64，并与客户端ID一起发送
	messageStr := clientID + ":" + base64.StdEncoding.EncodeToString(message)

	return s.client.Publish(s.ctx, channel, messageStr).Err()
}

// Close 关闭会话存储
func (s *RedisSessionStore) Close() error {
	// 取消上下文，停止消息监听器
	s.cancel()

	// 关闭消息订阅
	if s.pubsub != nil {
		s.pubsub.Close()
	}

	// 关闭Redis客户端
	return s.client.Close()
}

// ClientInfo 客户端信息
type ClientInfo struct {
	// 客户端ID
	ID string `json:"id"`

	// 服务器ID
	ServerID string `json:"server_id"`

	// 服务器地址，用于RPC调用
	ServerAddr string `json:"server_addr"`

	// 连接时间
	ConnectedAt time.Time `json:"connected_at"`
}

// MarshalBinary 实现encoding.BinaryMarshaler接口
func (c ClientInfo) MarshalBinary() ([]byte, error) {
	return json.Marshal(c)
}

// UnmarshalBinary 实现encoding.BinaryUnmarshaler接口
func (c *ClientInfo) UnmarshalBinary(data []byte) error {
	return json.Unmarshal(data, c)
}
